package cn.aitrox.ry.service.auth.service.impl;

import cn.aitrox.ry.bean.CommonPageInfo;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.bean.Like;
import cn.aitrox.ry.constant.CommonConstant;
import cn.aitrox.ry.enumtype.RespCodeEnum;
import cn.aitrox.ry.service.auth.dao.AuthPermissionDao;
import cn.aitrox.ry.service.auth.dao.AuthPermissionResourceDao;
import cn.aitrox.ry.service.auth.dao.AuthResourceDao;
import cn.aitrox.ry.service.auth.dao.AuthRolePermissionDao;
import cn.aitrox.ry.service.auth.dto.permission.in.AuthPermissionCreateInDto;
import cn.aitrox.ry.service.auth.dto.permission.in.AuthPermissionSearchInDto;
import cn.aitrox.ry.service.auth.dto.permission.in.AuthPermissionUpdateInDto;
import cn.aitrox.ry.service.auth.dto.permission.out.AuthPermissionDetailDto;
import cn.aitrox.ry.service.auth.dto.resource.out.AuthResourceDetailDto;
import cn.aitrox.ry.service.auth.entity.AuthPermissionEntity;
import cn.aitrox.ry.service.auth.entity.AuthPermissionResourceEntity;
import cn.aitrox.ry.service.auth.entity.AuthResourceEntity;
import cn.aitrox.ry.service.auth.po.permission.RolePermissionParamPo;
import cn.aitrox.ry.service.auth.service.AuthPermissionService;
import cn.aitrox.ry.util.ArrayUtil;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class AuthPermissionServiceImpl implements AuthPermissionService {

    @Autowired
    private AuthPermissionDao authPermissionDao;

    @Autowired
    private AuthResourceDao authResourceDao;

    @Autowired
    private AuthPermissionResourceDao authPermissionResourceDao;

    @Autowired
    private AuthRolePermissionDao authRolePermissionDao;

    @Transactional
    @Override
    public RespResult<Integer> create(AuthPermissionCreateInDto input) {
        String name = input.getName();
        List<Integer> resourceIds = input.getResourceIds();

        // 校验名称是否重复
        AuthPermissionEntity authPermissionEntity = authPermissionDao.findOne(new AuthPermissionEntity(null, name));
        if (null != authPermissionEntity) {
            return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "权限名称已存在");
        }

        // 校验资源ID是否存在
        if (!ArrayUtil.isEmpty(resourceIds)) {
            List<AuthResourceEntity> resourceEntityList = authResourceDao.findByIds(resourceIds.toArray(), null);
            List<Integer> resourceIdListInDB = resourceEntityList.stream().map(AuthResourceEntity::getId).collect(Collectors.toList());
            List<Integer> notExistResourceIds = resourceIds.stream().filter(resourceId -> !resourceIdListInDB.contains(resourceId)).collect(Collectors.toList());
            if (!ArrayUtil.isEmpty(notExistResourceIds)) {
                return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "资源不存在: " + StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, notExistResourceIds.toArray()));
            }
        }


        // 创建permission和 permission_resource
        authPermissionEntity = new AuthPermissionEntity(null, name);
        authPermissionDao.insertSelective(authPermissionEntity);
        Integer permissionId = authPermissionEntity.getId();

        List<AuthPermissionResourceEntity> authPermissionResourceEntityList = resourceIds.stream().map(resourceId -> new AuthPermissionResourceEntity(null, resourceId, permissionId)).collect(Collectors.toList());

        authPermissionResourceDao.batchInsert(authPermissionResourceEntityList);

        // 返回permissionId
        return RespResult.ok(permissionId);
    }

    @Transactional
    @Override
    public RespResult update(AuthPermissionUpdateInDto input) {
        // 校验权限是否存在
        AuthPermissionEntity authPermissionEntity = authPermissionDao.findById(input.getId());
        if (null == authPermissionEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "权限不存在");
        }

        // 校验权限名称是否存在
        if (null != input.getName()) {
            AuthPermissionEntity authPermissionEntityByName = authPermissionDao.findOne(new AuthPermissionEntity(null, input.getName()));
            if (null != authPermissionEntityByName && !input.getId().equals(authPermissionEntityByName.getId())) {
                return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "权限名称已存在");
            }
        }

        // permission_resource的删除、新增
        if (!ArrayUtil.isEmpty(input.getResourceIds())) {
            // 校验资源ID是否存在
            List<AuthResourceEntity> resourceEntityList = authResourceDao.findByIds(input.getResourceIds().toArray(), null);
            List<Integer> resourceIdListInDB = resourceEntityList.stream().map(AuthResourceEntity::getId).collect(Collectors.toList());
            List<Integer> notExistResourceIds = input.getResourceIds().stream().filter(resourceId -> !resourceIdListInDB.contains(resourceId)).collect(Collectors.toList());
            if (!ArrayUtil.isEmpty(notExistResourceIds)) {
                return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "资源不存在: " + StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, notExistResourceIds.toArray()));
            }


            List<AuthPermissionResourceEntity> permissionResourceList = authPermissionResourceDao.findByCondition(new AuthPermissionResourceEntity(null, null, input.getId()), null);
            List<Integer> resourceIdsInDB = permissionResourceList.stream().map(AuthPermissionResourceEntity::getResourceId).collect(Collectors.toList());

            // 传参有，但是数据库中没有的 就是新增的
            List<Integer> resourceIdsAdd = input.getResourceIds().stream().filter(resourceId -> !resourceIdsInDB.contains(resourceId)).collect(Collectors.toList());

            // 数据库有，但是传参中没有的 就是删除的
            List<Integer> resourceIdsRemove = resourceIdsInDB.stream().filter(resourceId -> !input.getResourceIds().contains(resourceId)).collect(Collectors.toList());

            if (!ArrayUtil.isEmpty(resourceIdsRemove)) {
                authPermissionResourceDao.deleteByPermissionIdResourceIds(input.getId(), resourceIdsRemove);
            }

            if (!ArrayUtil.isEmpty(resourceIdsAdd)) {
                authPermissionResourceDao.batchInsert(resourceIdsAdd.stream().map(resourceId -> new AuthPermissionResourceEntity(null, resourceId, authPermissionEntity.getId())).collect(Collectors.toList()));
            }
        }

        // 更新 permission
        if (null != input.getName()) {
            AuthPermissionEntity permissionUpdate = new AuthPermissionEntity(authPermissionEntity.getId(), input.getName());
            authPermissionDao.updateByIdSelective(permissionUpdate);
        }

        return RespResult.ok();
    }

    @Transactional
    @Override
    public RespResult delete(Integer id) {
        // 校验权限ID是否存在
        AuthPermissionEntity authPermissionEntity = authPermissionDao.findById(id);
        if (null == authPermissionEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "权限不存在");
        }

        // 删除permission、permission_resource、role_permission
        authPermissionDao.deleteById(id);

        authPermissionResourceDao.deleteByPermissionIdResourceIds(id, null);

        authRolePermissionDao.deleteByPermissionIds(Arrays.asList(id));

        return RespResult.ok();
    }

    @Override
    public RespResult<AuthPermissionDetailDto> read(Integer id) {
        AuthPermissionEntity authPermissionEntity = authPermissionDao.findById(id);
        if (null == authPermissionEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "权限不存在");
        }

        List<AuthPermissionResourceEntity> permissionResourceList = authPermissionResourceDao.findByCondition(new AuthPermissionResourceEntity(null, null, id), null);

        List<AuthResourceDetailDto> authResourceDetailList = null;

        if (!ArrayUtil.isEmpty(permissionResourceList)) {
            List<AuthResourceEntity> allResourceEntity = authResourceDao.findAll();
            authResourceDetailList = permissionResourceList.stream().map(x -> this.getAuthResourceDetail(x.getResourceId(), allResourceEntity)).collect(Collectors.toList());
        }

        return RespResult.ok(new AuthPermissionDetailDto(authPermissionEntity.getId(), authPermissionEntity.getName(), authResourceDetailList, authPermissionEntity.getCreateTime(), authPermissionEntity.getUpdateTime()));
    }

    @Override
    public AuthResourceDetailDto getAuthResourceDetail(Integer resourceId, List<AuthResourceEntity> allResourceEntity) {
        if (null == resourceId || ArrayUtil.isEmpty(allResourceEntity)) {
            return null;
        }
        AuthResourceEntity authResourceEntity = allResourceEntity.stream().filter(x -> x.getParentId().equals(resourceId)).findFirst().orElse(null);
        AuthResourceDetailDto authResourceDetail = new AuthResourceDetailDto(authResourceEntity.getId(), authResourceEntity.getCode(), authResourceEntity.getParentId(), authResourceEntity.getName(), authResourceEntity.getType(), authResourceEntity.getDescription(), authResourceEntity.getApiUri(), authResourceEntity.getApiMethod(), authResourceEntity.getCreateTime(), authResourceEntity.getUpdateTime(), new ArrayList<>());

        List<AuthResourceEntity> childResourceEntityList = allResourceEntity.stream().filter(x -> x.getParentId().equals(resourceId)).collect(Collectors.toList());
        if (ArrayUtil.isEmpty(childResourceEntityList)) {
            return authResourceDetail;
        }

        for (AuthResourceEntity childEntity : childResourceEntityList) {
            authResourceDetail.getChilds().add(this.getAuthResourceDetail(childEntity.getId(), allResourceEntity));
        }

        return authResourceDetail;
    }

    @Override
    public CommonPageInfo<AuthPermissionDetailDto> search(AuthPermissionSearchInDto input) {
        PageInfo<AuthPermissionEntity> pageInfo = authPermissionDao.searchByParam(input.getPage(), input.getPageSize(), new RolePermissionParamPo(Like.joinLikeKeyword(input.getName())));
        if (!ArrayUtil.isEmpty(pageInfo.getList())) {
            return new CommonPageInfo(pageInfo.getTotal(), pageInfo.getPages(), null);
        }

        List<Integer> permissionIdList = pageInfo.getList().stream().map(AuthPermissionEntity::getId).collect(Collectors.toList());
        List<AuthPermissionResourceEntity> permissionResourceEntityList = authPermissionResourceDao.findByPermissionIds(permissionIdList);
        List<Integer> resourceIdList = permissionResourceEntityList.stream().map(AuthPermissionResourceEntity::getResourceId).distinct().collect(Collectors.toList());
        List<AuthResourceEntity> resourceEntityList = authResourceDao.findByIds(resourceIdList.toArray(), null);

        Map<Integer, List<Integer>> permissionIdReourceIdsMap = permissionResourceEntityList.stream().collect(Collectors.groupingBy(AuthPermissionResourceEntity::getPermissionId, Collectors.mapping(AuthPermissionResourceEntity::getResourceId, Collectors.toList())));

        List<AuthPermissionDetailDto> list = pageInfo.getList().stream().map(x -> {
            List<AuthResourceDetailDto> resourceList = null;
            List<Integer> resourceIdByPermission = permissionIdReourceIdsMap.get(x.getId());
            if (!ArrayUtil.isEmpty(resourceIdByPermission)) {
                List<AuthResourceEntity> resourceByPermission = resourceEntityList.stream().filter(resourceId -> resourceIdByPermission.contains(resourceId)).collect(Collectors.toList());
                resourceList = resourceByPermission.stream().map(y -> this.getAuthResourceDetail(y.getId(), resourceByPermission)).collect(Collectors.toList());
            }
            return new AuthPermissionDetailDto(x.getId(), x.getName(), resourceList, x.getCreateTime(), x.getUpdateTime());
        }).collect(Collectors.toList());
        return new CommonPageInfo(pageInfo.getTotal(), pageInfo.getPages(), list);

    }

}
